<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>持久化变更 | Elasticsearch: 权威指南 | Elastic</title>
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
</head>
<body>
<div class="main-container">
    <section id="content">
        
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原文地址: <a href="https://www.elastic.co/guide/cn/elasticsearch/guide/current/translog.html" rel="nofollow">https://www.elastic.co/guide/cn/elasticsearch/guide/current/translog.html</a>, 版权归 www.elastic.co 所有<br/>
                            英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/translog.html" rel="nofollow">https://www.elastic.co/guide/en/elasticsearch/guide/current/translog.html</a>
                            </div>
                        <!-- start body -->
                  <div class="page_header">
<b>请注意:</b><br>本书基于 Elasticsearch 2.x 版本，有些内容可能已经过时。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch: 权威指南</a></span>
»
<span class="breadcrumb-link"><a href="getting-started.html">基础入门</a></span>
»
<span class="breadcrumb-link"><a href="inside-a-shard.html">分片内部原理</a></span>
»
<span class="breadcrumb-node">持久化变更</span>
</div>
<div class="navheader">
<span class="prev">
<a href="near-real-time.html">« 近实时搜索</a>
</span>
<span class="next">
<a href="merge-process.html">段合并 »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="translog"></a>持久化变更<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/075_Inside_a_shard/50_Persistent_changes.asciidoc">edit</a>
</h2>
</div></div></div>
<p>如果没有用 <code class="literal">fsync</code> 把数据从文件系统缓存刷（flush）到硬盘，我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证 Elasticsearch 的可靠性，需要确保数据变化被持久化到磁盘。</p>
<p>在 <a class="xref" href="dynamic-indices.html" title="动态更新索引">动态更新索引</a>，我们说一次完整的提交会将段刷到磁盘，并写入一个包含所有段列表的提交点。Elasticsearch 在启动或重新打开一个索引的过程中使用这个提交点来判断哪些段隶属于当前分片。</p>
<p>即使通过每秒刷新（refresh）实现了近实时搜索，我们仍然需要经常进行完整提交来确保能从失败中恢复。但在两次提交之间发生变化的文档怎么办？我们也不希望丢失掉这些数据。</p>
<p>Elasticsearch 增加了一个 <em>translog</em> ，或者叫事务日志，在每一次对 Elasticsearch 进行操作时均进行了日志记录。通过 translog ，整个流程看起来是下面这样：</p>
<div class="olist orderedlist">
<ol class="orderedlist">
<li class="listitem">
<p>一个文档被索引之后，就会被添加到内存缓冲区，<em>并且</em> 追加到了 translog ，正如 <a class="xref" href="translog.html#img-xlog-pre-refresh" title="新的文档被添加到内存缓冲区并且被追加到了事务日志">Figure 21, “新的文档被添加到内存缓冲区并且被追加到了事务日志”</a> 描述的一样。</p>
<div id="img-xlog-pre-refresh" class="imageblock">
<div class="content">
<img src="../images/elas_1106.png" alt="New documents are added to the in-memory buffer and appended to the transaction log">
</div>
<div class="title">Figure 21. 新的文档被添加到内存缓冲区并且被追加到了事务日志</div>
</div>
</li>
<li class="listitem">
<p>刷新（refresh）使分片处于 <a class="xref" href="translog.html#img-xlog-post-refresh" title="刷新（refresh）完成后, 缓存被清空但是事务日志不会">Figure 22, “刷新（refresh）完成后, 缓存被清空但是事务日志不会”</a> 描述的状态，分片每秒被刷新（refresh）一次：</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
这些在内存缓冲区的文档被写入到一个新的段中，且没有进行 <code class="literal">fsync</code> 操作。
</li>
<li class="listitem">
这个段被打开，使其可被搜索。
</li>
<li class="listitem">
内存缓冲区被清空。
</li>
</ul>
</div>
<div id="img-xlog-post-refresh" class="imageblock">
<div class="content">
<img src="../images/elas_1107.png" alt="After a refresh, the buffer is cleared but the transaction log is not">
</div>
<div class="title">Figure 22. 刷新（refresh）完成后, 缓存被清空但是事务日志不会</div>
</div>
</li>
<li class="listitem">
<p>这个进程继续工作，更多的文档被添加到内存缓冲区和追加到事务日志（见 <a class="xref" href="translog.html#img-xlog-pre-flush" title="事务日志不断积累文档">Figure 23, “事务日志不断积累文档”</a> ）。</p>
<div id="img-xlog-pre-flush" class="imageblock">
<div class="content">
<img src="../images/elas_1108.png" alt="The transaction log keeps accumulating documents">
</div>
<div class="title">Figure 23. 事务日志不断积累文档</div>
</div>
</li>
<li class="listitem">
<p>每隔一段时间—​例如 translog 变得越来越大—​索引被刷新（flush）；一个新的 translog 被创建，并且一个全量提交被执行（见 <a class="xref" href="translog.html#img-xlog-post-flush" title="在刷新（flush）之后，段被全量提交，并且事务日志被清空">Figure 24, “在刷新（flush）之后，段被全量提交，并且事务日志被清空”</a> ）：</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
所有在内存缓冲区的文档都被写入一个新的段。
</li>
<li class="listitem">
缓冲区被清空。
</li>
<li class="listitem">
一个提交点被写入硬盘。
</li>
<li class="listitem">
文件系统缓存通过 <code class="literal">fsync</code> 被刷新（flush）。
</li>
<li class="listitem">
老的 translog 被删除。
</li>
</ul>
</div>
</li>
</ol>
</div>
<p>translog 提供所有还没有被刷到磁盘的操作的一个持久化纪录。当 Elasticsearch 启动的时候，
它会从磁盘中使用最后一个提交点去恢复已知的段，并且会重放 translog 中所有在最后一次提交后发生的变更操作。</p>
<p>translog 也被用来提供实时 CRUD 。当你试着通过ID查询、更新、删除一个文档，它会在尝试从相应的段中检索之前，
首先检查 translog 任何最近的变更。这意味着它总是能够实时地获取到文档的最新版本。</p>
<div id="img-xlog-post-flush" class="imageblock">
<div class="content">
<img src="../images/elas_1109.png" alt="After a flush, the segments are fully commited and the transaction log is cleared">
</div>
<div class="title">Figure 24. 在刷新（flush）之后，段被全量提交，并且事务日志被清空</div>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="flush-api"></a>flush API<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/075_Inside_a_shard/50_Persistent_changes.asciidoc">edit</a>
</h3>
</div></div></div>
<p>这个执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 <em>flush</em> 。
分片每30分钟被自动刷新（flush），或者在 translog 太大的时候也会刷新。请查看
 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/2.4/index-modules-translog.html#_translog_settings" class="ulink" target="_top"><code class="literal">translog</code> 文档</a> 来设置，它可以用来
 控制这些阈值：</p>
<p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/5.6/indices-flush.html" class="ulink" target="_top"><code class="literal">flush</code> API</a> 可以被用来执行一个手工的刷新（flush）:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">POST /blogs/_flush <a id="CO40-1"></a><i class="conum" data-value="1"></i>

POST /_flush?wait_for_ongoing <a id="CO40-2"></a><i class="conum" data-value="2"></i></pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO40-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>刷新（flush） <code class="literal">blogs</code> 索引。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO40-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>刷新（flush）所有的索引并且并且等待所有刷新在返回前完成。</p>
</td>
</tr>
</table>
</div>
<p>你很少需要自己手动执行 <code class="literal">flush</code> 操作；通常情况下，自动刷新就足够了。</p>
<p>这就是说，在重启节点或关闭索引之前执行 <a class="xref" href="translog.html#flush-api" title="flush API">flush</a> 有益于你的索引。当 Elasticsearch 尝试恢复或重新打开一个索引，
它需要重放 translog 中所有的操作，所以如果日志越短，恢复越快。</p>
<div class="sidebar">
<a id="how-safe-is-the-translog"></a>
<div class="titlepage"><div><div>
<p class="title"><strong>Translog 有多安全?</strong></p>
</div></div></div>
<p>translog 的目的是保证操作不会丢失。这引出了这个问题： Translog 有多安全？</p>
<p>在文件被 <code class="literal">fsync</code> 到磁盘前，被写入的文件在重启之后就会丢失。默认 translog 是每 5 秒被 <code class="literal">fsync</code> 刷新到硬盘，
或者在每次写请求完成之后执行(e.g. index, delete, update, bulk)。这个过程在主分片和复制分片都会发生。最终，
基本上，这意味着在整个请求被 <code class="literal">fsync</code> 到主分片和复制分片的translog之前，你的客户端不会得到一个 200 OK 响应。</p>
<p>在每次请求后都执行一个 fsync 会带来一些性能损失，尽管实践表明这种损失相对较小（特别是bulk导入，它在一次请求中平摊了大量文档的开销）。</p>
<p>但是对于一些大容量的偶尔丢失几秒数据问题也并不严重的集群，使用异步的 fsync 还是比较有益的。比如，写入的数据被缓存到内存中，再每5秒执行一次 <code class="literal">fsync</code> 。</p>
<p>这个行为可以通过设置 <code class="literal">durability</code> 参数为 <code class="literal">async</code> 来启用：</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">PUT /my_index/_settings
{
    "index.translog.durability": "async",
    "index.translog.sync_interval": "5s"
}</pre>
</div>
<p>这个选项可以针对索引单独设置，并且可以动态进行修改。如果你决定使用异步 translog 的话，你需要 <em>保证</em> 在发生crash时，丢失掉 <code class="literal">sync_interval</code> 时间段的数据也无所谓。请在决定前知晓这个特性。</p>
<p>如果你不确定这个行为的后果，最好是使用默认的参数（ <code class="literal">"index.translog.durability": "request"</code> ）来避免数据丢失。</p>
</div>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="near-real-time.html">« 近实时搜索</a>
</span>
<span class="next">
<a href="merge-process.html">段合并 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>